﻿using System;
using System.Reflection;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using System.CodeDom.Compiler;

namespace EclipseLib.Shared.Scripting
{
    public class GameAssembly
    {
        // Data Members
        Assembly ScriptAssembly = null;
        Type ClassType;
        MethodInfo Method;
        object Obj;
        GameScript Script;

        // Member Properties
        public object ScriptObject
        {
            get { return Obj; }
        }

        // Constructors
        public GameAssembly(GameScript ScriptToCompile)
        {
            Script = ScriptToCompile;
        }

        // Methods
        public CompilerResults CompileScript()
        {
            // Build Assembly
            CSharpCodeProvider Provider = new CSharpCodeProvider();
            ICodeCompiler Compiler = Provider.CreateCompiler();
            CompilerParameters Parameters = new CompilerParameters()
            {
                GenerateInMemory = true,
                TreatWarningsAsErrors = false,
                WarningLevel = 4,
                CompilerOptions = "/optimize"
            };

            for (int i = 0; i < Script.References.Count; ++i)
                Parameters.ReferencedAssemblies.Add(Script.References[i]);

            CompilerResults Results = Compiler.CompileAssemblyFromSource(Parameters, Script.Code);

            if (Results.Errors.Count > 0)
                return Results;

            ScriptAssembly = Results.CompiledAssembly;

            ClassType = ScriptAssembly.GetType(Script.Class);
            Method = ClassType.GetMethod(Script.Function);
            Obj = Activator.CreateInstance(ClassType);
            return Results;
        }
        public T GetProperty<T>(string PropertyName, object[] Index = null)
        {
            return (T)(ClassType.GetProperty(PropertyName).GetValue(Obj, Index));
        }
        public void SetProperty(string PropertyName, object Value, object[] Index = null)
        {
            ClassType.GetProperty(PropertyName).SetValue(Obj, Value, Index);
        }
        public object Run(params object[] Args)
        {
            return Method.Invoke(Obj, Args);
        }
    }
}
